package cn.shiro.shiroservice.auth.config;

import cn.shiro.shiroservice.auth.provider.core.ShiroDefaultWebSessionManager;
import cn.shiro.shiroservice.auth.provider.interfaces.impl.DefaultCacheManager;
import cn.shiro.shiroservice.auth.provider.interfaces.impl.SimpleRealmImpl;
import cn.shiro.shiroservice.auth.service.impl.ISessionManager;
import cn.shiro.shiroservice.common.constant.HttpRequestManaPoint;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * shiro配置
 * &#064;Time 2023 十二月 星期四 13:56
 *
 * @author ShangGuan
 * @date 2023/12/21
 */
@Configuration
public class ShiroConfig {

    /**
     * 设置安全管理器
     * 设置默认web安全管理器
     *
     * @param cookieRememberMeManager 记住我
     * @param iRealm                  i领域
     * @param sessionManager          会话管理器
     * @return {@link java.lang.SecurityManager}
     */


    @Bean("securityManager")
    public SecurityManager setSecurityManager(
            @Qualifier("cookieRememberMeManager") CookieRememberMeManager cookieRememberMeManager,
            @Qualifier("iRealmImpl") SimpleRealmImpl iRealm,
            @Qualifier("defaultWebSessionManager") DefaultWebSessionManager sessionManager
    ) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置记住我管理器
        securityManager.setRealm(iRealm);
        securityManager.setRememberMeManager(cookieRememberMeManager);
        securityManager.setSessionManager(sessionManager);
        //将securityManager绑定在线程上
        ThreadContext.bind(securityManager);
        return securityManager;
    }


    /**
     * 自定义shiro过滤器参数bean，覆盖默认的
     *
     * @return {@link ShiroFilterChainDefinition}
     */
    @Bean("shiroFilterChainDefinition")
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
        //开启shiro内置的退出过滤器，完成退出功能
        definition.addPathDefinition("/logout", "logout");//退出路径
//        definition.addPathDefinition("/auth/save", "authcBasic"); //该过滤器处理基本的 HTTP 身份验证，通常用于处理 HTTP Basic
//        definition.addPathDefinition("/auth/save", "authcBearer"); //该过滤器处理 Bearer Token 身份验证，通常用于处理基于令牌的身份验证
//        definition.addPathDefinition("/auth/save", "anon");
//        definition.addPathDefinition("/**", "user"); //表示一下路径会记住我
        definition.addPathDefinition("/**", "anon");
        return definition;
    }


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(
            @Qualifier("securityManager") SecurityManager securityManager,
            @Qualifier("shiroFilterChainDefinition") ShiroFilterChainDefinition shiroFilterChainDefinition) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setLoginUrl(HttpRequestManaPoint.HTTP_PREFIX + "/auth/login");
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
        return shiroFilterFactoryBean;
    }


    /**
     * 设置会话管理器
     *
     * @param iSessionManager i会话管理器
     * @return {@link ShiroDefaultWebSessionManager}
     */

    @Bean("defaultWebSessionManager")
    public ShiroDefaultWebSessionManager setSessionManager(@Qualifier("iSessionManager") ISessionManager iSessionManager
            , @Qualifier("defaultCacheManager") DefaultCacheManager defaultCacheManager) {
        ShiroDefaultWebSessionManager sessionManager = new ShiroDefaultWebSessionManager();
        //设置session过期时间
        sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
//        定期验证session
        sessionManager.setSessionValidationSchedulerEnabled(true);
//        删除无效session
        sessionManager.setDeleteInvalidSessions(true);
//         去掉shiro登录时url里的JSESSIONID
        sessionManager.setSessionIdUrlRewritingEnabled(false);
//        设置sessionDAO 将shiro的session交给iSessionManager管理
        sessionManager.setSessionDAO(iSessionManager);
        sessionManager.setCacheManager(defaultCacheManager);
        sessionManager.setSessionIdCookieEnabled(false);
        return sessionManager;
    }

    /**
     * 开启Shiro注解(如@RequiresRoles,@RequiresPermissions),
     * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        /*
         * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
         * 在@Controller注解的类的方法中加入@RequiresRole注解，会导致该方法无法映射请求，导致返回404。
         * 加入这项配置能解决这个bug
         */
        advisorAutoProxyCreator.setUsePrefix(true);
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启aop注解支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


}
